rendernode: Avoid rounding errors
authorBenjamin Otte <otte@redhat.com>
Wed, 12 Feb 2020 17:44:11 +0000 (18:44 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 13 Feb 2020 06:36:38 +0000 (07:36 +0100)
Compute the pattern matrix directly instead of transforming the cairo_t.

This ensures that when node_size / texture_size is some obscure floating
point value, we don't get rounding issues from scaling by it once we
draw the texture_size rectangle.

I have no actual failure where this comes in handy, but I had written
the code anyway, so decided to keep it.

gsk/gskrendernodeimpl.c

index a6957ff657c87dcbb8ae24b062487507e038eb5f..43844cd1e2df07f0e547b95ba3618bf6dbf1d3cf 100644 (file)
@@ -638,28 +638,28 @@ gsk_texture_node_draw (GskRenderNode *node,
   GskTextureNode *self = (GskTextureNode *) node;
   cairo_surface_t *surface;
   cairo_pattern_t *pattern;
+  cairo_matrix_t matrix;
 
   surface = gdk_texture_download_surface (self->texture);
-
-  cairo_save (cr);
-
-  cairo_translate (cr, node->bounds.origin.x, node->bounds.origin.y);
-  cairo_scale (cr,
-               node->bounds.size.width / gdk_texture_get_width (self->texture),
-               node->bounds.size.height / gdk_texture_get_height (self->texture));
-
   pattern = cairo_pattern_create_for_surface (surface);
   cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
-  cairo_set_source (cr, pattern);
-  cairo_rectangle (cr,
-                   0, 0,
-                   gdk_texture_get_width (self->texture), gdk_texture_get_height (self->texture));
-  cairo_fill (cr);
 
-  cairo_restore (cr);
+  cairo_matrix_init_scale (&matrix,
+                           gdk_texture_get_width (self->texture) / node->bounds.size.width,
+                           gdk_texture_get_height (self->texture) / node->bounds.size.height);
+  cairo_matrix_translate (&matrix,
+                          -node->bounds.origin.x,
+                          -node->bounds.origin.y);
+  cairo_pattern_set_matrix (pattern, &matrix);
 
+  cairo_set_source (cr, pattern);
   cairo_pattern_destroy (pattern);
   cairo_surface_destroy (surface);
+
+  cairo_rectangle (cr,
+                   node->bounds.origin.x, node->bounds.origin.y,
+                   node->bounds.size.width, node->bounds.size.height);
+  cairo_fill (cr);
 }
 
 static void